#include <avr/pgmspace.h>
#include <avrpins.h>
#include <max3421e.h>
#include <usbhost.h>
#include <usb_ch9.h>
#include <Usb.h>
#include <usbhub.h>
#include <avr/pgmspace.h>
#include <address.h>
#include <hidboot.h>
#include <printhex.h>
#include <message.h>
#include <hexdump.h>
#include <parsetools.h>
#include <SoftwareSerial.h>
//The USB Host Shield is using just about every digital port on the Arduino. I think 5 and 8 are still available
//for driving the door lock circuit. It is recommended that we use a 9 Volt wall wart to ensure enough power to
//drive the USB and RFID boards.
#define rxPin 6 //setup for SoftwareSerial port through digital pins
#define txPin 4 //setup for SoftwareSerial port through digital pins
#define transistor_pin 5 //this pin will drive a transistor for activating the relay to the door strike
#define door_switch_pin 3 //this pin is feedback for whether the door is open
#define TAG_LEN 12
#define NUM_TAGS 8
// set up a new serial
SoftwareSerial mySerial =  SoftwareSerial(rxPin, txPin);

byte RFIDcode[TAG_LEN][NUM_TAGS];		 // var that will hold the bytes-in read from the serialBuffer
int RFID_bytes_read = 0, card_index=0, card_flag=0;
char ID_string[256]; //Track 2 is ~75 bytes per inch or ~225 total bytes.
byte reset_to_ready[6] = {0x05,0x03,0x03,0x26,0x1B,0x61};
byte tagAquiet[14]={0x0D,0x00,0x23,0x02,0xEE,0xE9,0x8A,0x12,0x00,0x01,0x04,0xE0,0xC7,0x3F};
byte tagBquiet[14]={0x0D,0x00,0x23,0x02,0xF1,0x6F,0x8A,0x12,0x00,0x01,0x04,0xE0,0xDD,0x0B};
byte tagCquiet[14]={0x0D,0x00,0x23,0x02,0x85,0xF1,0x8A,0x12,0x00,0x01,0x04,0xE0,0x8F,0x20};
byte tagDquiet[14]={0x0D,0x00,0x23,0x02,0x8D,0xEF,0x8A,0x12,0x00,0x01,0x04,0xE0,0xDB,0x3E};
byte tagEquiet[14]={0x0D,0x00,0x23,0x02,0xC3,0xFE,0x8A,0x12,0x00,0x01,0x04,0xE0,0x3B,0x41};
byte tagFquiet[14]={0x0D,0x00,0x23,0x02,0xFE,0xB4,0x8A,0x12,0x00,0x01,0x04,0xE0,0x3F,0x38};
byte tagGquiet[14]={0x0D,0x00,0x23,0x02,0x48,0xB2,0x8A,0x12,0x00,0x01,0x04,0xE0,0x29,0x5B};
byte tagHquiet[14]={0x0D,0x00,0x23,0x02,0x09,0xD8,0x8a,0x12,0x00,0x01,0x04,0xE0,0xB5,0xF2};
//Tag Identifiers. The last two bytes (CRC) change when in a command
//A) 0000eee98a12000104e0e17c
//B) 0000f16f8a12000104e0fb48
//C) 000085f18a12000104e0a963
//D) 00008def8a12000104e0fd7d
//E) 0000c3fe8a12000104e01d02
//F) 0000feb48a12000104e0197b
//G) 000048b28a12000104e00f18
//H) 000009d88a12000104e093b1

//Next few functions are for dealing with data coming from the ID card reader through the USB Host Shield.
//Requires USBHost2 library.
//The ID card reader stuff could probably be greatly simplified, but I'm lazy.
class KbdRptParser : public KeyboardReportParser
{
        void PrintKey(uint8_t mod, uint8_t key);
        
protected:
	virtual void OnKeyDown	(uint8_t mod, uint8_t key);
	virtual void OnKeyUp	(uint8_t mod, uint8_t key);
	virtual void OnKeyPressed(uint8_t key);
};

void KbdRptParser::PrintKey(uint8_t m, uint8_t key)	
{
    MODIFIERKEYS mod;
    *((uint8_t*)&mod) = m;
};

void KbdRptParser::OnKeyDown(uint8_t mod, uint8_t key)	
{
////    Serial.print("DN ");
    PrintKey(mod, key);
    uint8_t c = OemToAscii(mod, key);
    
    if (c)
        OnKeyPressed(c);
}

void KbdRptParser::OnKeyUp(uint8_t mod, uint8_t key)	
{
//    Serial.print("UP ");
    PrintKey(mod, key);
}

void KbdRptParser::OnKeyPressed(uint8_t key)	
{
//    Serial.print("ASCII: ");
//    Serial.print((char)key);
//  Store the card information in an array.
    ID_string[card_index] = char(key);
    Serial.print(ID_string[card_index]); //print the data to the serial port
    card_flag = 1;
    card_index++;
};

//Function to read RFID tags. Requires the Stay_Quiet function for turning off tags sequentially.
//This is still a brute force method calling only known 8 tags.
void read_RFID(){
  int index, yy, xx;
  RFID_bytes_read = 0;
  Serial.println("Reading RFID tags");
  mySerial.write(0xfd);
  delay(500);
  for (xx=1; xx<NUM_TAGS+1; xx++){
    mySerial.write(0xf7); //transmitter off
    delay(100);
    mySerial.write(0xf8); //transmitter on
    delay(100);
    mySerial.write(reset_to_ready, 6);
    delay(100);  
    for (yy=1; yy<NUM_TAGS+1; yy++) {
      if(xx != yy) {
        Stay_Quiet(yy);
      }
    }
    mySerial.flush();
    delay(100);
    mySerial.write(0xfa);
    delay(100);
    if(mySerial.available());{
      for(index=0; index<TAG_LEN; index++){
        RFIDcode[index][xx] = mySerial.read();
//        delay(100);
        Serial.print(RFIDcode[index][xx],HEX);
        RFID_bytes_read++;
      }
      Serial.println();
    }
  }
  mySerial.write(0xfc);
  delay(500);
  Serial.flush();
}

//Function to tell a tag to be quiet
byte Stay_Quiet(int tag)
{
//  "Tell a tag to shut up
  if (tag == 1){
    //Tag A: eee98a12000104e0 \ e17c
    mySerial.write(tagAquiet,14);
  }
  else if(tag == 2){
    //Tag B: f16f8a12000104e0 \ fb48
    mySerial.write(tagBquiet,14);
  }
  else if(tag == 3){
    //Tag C: 85f18a12000104e0 \ a963
    mySerial.write(tagCquiet,14);
  }
  else if(tag == 4){
    //Tag D: 8def8a12000104e0 \ fd7d
    mySerial.write(tagDquiet,14);
  }
  else if(tag == 5){
    //Tag E: c3fe8a12000104e0 \ 1d02
    mySerial.write(tagEquiet,14);
  }
  else if(tag == 6){
    //Tag F: feb48a12000104e0 \ 197b
    mySerial.write(tagFquiet,14);
  }
  else if(tag == 7){
    //Tag G: 48b28a12000104e0 \ 0f18
    mySerial.write(tagGquiet,14);
  }
  else if(tag == 8){
    //Tag H: 09d88a12000104e0 \ 93b1
    mySerial.write(tagHquiet,14);
  }
  else{
    return 0;
  }
  delay(100);
}

//Function to check if the door is open. Returns 1 if it's open, 0 if it's closed.
int door_open()
{
  int val;
  val = digitalRead(door_switch_pin);
  if (val) //read a 1 on the door pin means the door is closed
    return 0;
  else
    return 1; //read a 0 on the door pin means the door is open
}

USB     Usb;
//USBHub     Hub(&Usb);
HIDBoot<HID_PROTOCOL_KEYBOARD>    Keyboard(&Usb);

uint32_t next_time;

KbdRptParser Prs;

void setup(){
   // define pin modes for tx, rx, transistor, door switch pins:
  pinMode(rxPin, INPUT);
  pinMode(txPin, OUTPUT);
  pinMode(transistor_pin, OUTPUT);
  pinMode(door_switch_pin, INPUT);
  mySerial.begin(19200); // set the data rate for the SoftwareSerial port
  delay(200);
  Serial.begin( 19200 ); //Initialize the Arduino serial port
  delay(200);
  if (Usb.Init() == -1)
    Serial.println("OSC did not start.");
  delay( 200 );
  next_time = millis() + 5000;
  
  Keyboard.SetReportParser(0, (HIDReportParser*)&Prs);
}

void loop()
{
  ID_string[0] = ' ';
//  read_RFID(); //This isn't right place for this.
  delay(100);
  Usb.Task();
  if(ID_string[0] != ' ')
  {
    Serial.println("ID Card being read.");
    while(card_index<62)
    { //loop until an ID card is read. There has to be a simpler/better way for us to see if data is being send from the swipe.
     Usb.Task(); //Check the USB port for magstripe data.
    }
    Serial.println();
    if(door_open()==0)//if the door is closed, check for card swipes
    {
      if(card_flag){ //ID card data was read. Should update this with validation flag rather than just any card
        //Need code for checking the ID card
        //Code for opening the box and checking if the box is open.
        Serial.println("ELECTRIFY!!!");
        digitalWrite(transistor_pin, HIGH);
        delay(5000);
        digitalWrite(transistor_pin, LOW);
        delay(5000);
      }
      read_RFID(); //This isn't right. Requires a card swipe to update the RFID list.
    }
    if(door_open()==1) //else if the door is open, let the user know
    {
      Serial.println("Door is open, can't do anything.");
      delay(5000);
    }
    card_flag = 0;
  }
    card_index=0; //zero the index for filling the card information array
}

